import { computed } from 'vue';
import { Player } from "@/core/playersystem/player";
import { PhaseEnum } from "@/core/playersystem/phase";
import { Card, CardType, Color, Equipment } from "@/core/cardsystem/card";
import { GameManager } from "@/core/gamesystem/gameManager";
import { Chitu, JueYing } from '@/core/cardsystem/equipments/horses';
import { DelayBrilliantness } from '@/core/cardsystem/brilliantness/delay';
import { DefaultRequestProxyFactory } from '@/core/playersystem/handlers';
import store from '.';

export class CardView {
    card: Card
    numberInfo: string
    cardInfo: string
    textColor: string
    selected: boolean
    canPick: boolean

    constructor(card: Card) {
        this.card = card
        this.numberInfo = card.colorCN() + " " + card.numberCN()
        this.cardInfo = card.info()
        this.textColor = card.isRed() ? 'redtxt' : 'balcktxt'
        this.selected = false
        this.canPick = false
    }

    canuseCls():string {
        return this.canPick ? '': 'disable'
    }

    selectedCls():string {
        return this.selected ? 'selected':''
    }

    selectCard() {
        this.selected = !this.selected
    }

}

export class EquipView extends CardView {

    owner: PlayerView

    constructor(card: Card, owner: PlayerView) {
        super(card)
        this.owner = owner
    }

    canuseCls():string {
        return this.canPick ? 'viewable': 'disable'
    }

    selectedCls():string {
        return this.selected ? 'selected':''
    }

}

export class DelayBrilliantnessView extends CardView {

    owner: PlayerView

    brief: string

    constructor(card: DelayBrilliantness, owner: PlayerView) {
        super(card)
        this.owner = owner
        this.brief = card.brief()
    }

    canuseCls():string {
        return this.canPick ? 'viewable': 'disable'
    }

    selectedCls():string {
        return this.selected ? 'equipselected':''
    }

}


export class PlayerView {
    player: Player
    name: string
    selected: boolean
    canPick: boolean
    equipmentAreas: (EquipView|null)[]
    judgeAreas: DelayBrilliantnessView[]
    isCurrent: boolean
    isSpecify: boolean
    hpReduce: boolean
    isFirst: boolean
    isLast: boolean
    positionCls: string

    constructor(player: Player, isCurrent=false, isFirst=false, isLast=false) {
        this.player = player
        this.name = player.name
        this.canPick = false
        this.selected = false
        this.equipmentAreas = this.parseEquipmentAreas()
        this.judgeAreas = this.parseJudgeAreas()
        this.isCurrent = isCurrent
        this.isSpecify = false
        this.hpReduce = false
        this.isFirst = isFirst
        this.isLast = isLast
        this.positionCls = isFirst ? 'player-item-left' : isLast ? 'player-item-right' : ''
    }

    canuseCls() {
        return this.canPick ? 'canpick': ''
    }

    currentCls() {
        return this.isCurrent ? 'current-player' : ''
    }

    bespecifyCls() {
        return this.isSpecify && !this.isCurrent ? 'bespecify' : ''
    }

    hpReduceCls() {
        return this.hpReduce ? 'bespecify' : ''
    }

    selectedCls() {
        return this.selected ? 'selected':''
    }

    pick() {
        this.selected = !this.selected
    }

    handCardCount(): number {
        return this.player.handCardAreas.handCardCount()
    }

    hpInfo(): string {
        return `${this.player.currentHP} / ${this.player.maxHP}`
    }

    parseEquipmentAreas(): (EquipView|null)[] {
        const equipmentArea = this.player.equipmentAreas.equipmentArea
        const res = []
        for(const equip of equipmentArea) {
            const item = equip ? new EquipView(equip, this) : null
            res.push(item)
        }

        return res
    }

    parseJudgeAreas(): DelayBrilliantnessView[] {
        const judgeArea = this.player.judgeAreaController.judgeArea
        const res = []
        for (const item of judgeArea) {
            res.push(new DelayBrilliantnessView(item, this))
        }
        return res
    }

}

export class GameView {
    gameManager: GameManager

    constructor(gameManager: GameManager) {
        this.gameManager = gameManager
    }

    parsePlayerView(): PlayerView[] {
        const pls:Player[] = this.gameManager.allPlayerExceptMainRole()
        const current = this.gameManager.current.player
        const res = pls.map((t, index) => new PlayerView(t, t.equals(current), index === 0, index === pls.length - 1))
        return res
    }

    parseMainRolePlayerView(): PlayerView {
        return new PlayerView( this.gameManager.mainRolePlayer())
    }

    parseMainRoleCardView(): CardView[] {
        const mainRolePlayer = this.gameManager.mainRolePlayer()
        const handCards = mainRolePlayer.handCardAreas.handCards
        const res = handCards.map(t => new CardView(t))
        return res
    }

}

export interface DeskCardInfoView {
    firstLine: string,
    nextLine: string,
    lastLine: string
}

interface TipTab {
    onshow: boolean,
    tiptxt: string
}

interface selectorAreas {
    onshow: boolean,
    
}

export interface GameViewState {
    players: PlayerView[],
    mainRolePlayer: PlayerView | null,
    mainRoleHandCards: CardView[],
    canPickMin: number
    canPickMax: number
    logs: string[]
    deskCards: DeskCardInfoView[]
    tiptab: TipTab
}

function updateView0(commit: any, payload: GameView) {
    const playerView = payload.parsePlayerView()
    const mainRoleHandCards = payload.parseMainRoleCardView()
    const mainRolePlayer = payload.parseMainRolePlayerView()
    
    commit('setPlayers', playerView)
    commit('setMainRoleHandCards', mainRoleHandCards)
    commit('setMainRolePlayer', mainRolePlayer)
    // commit('setLogs', logs.slice(-100))
}

export default {
    namespaced: true,
    state: (): GameViewState => ({
        players: [],
        mainRolePlayer: null,
        mainRoleHandCards: [],
        canPickMin: 0,
        canPickMax: 0,
        logs: [],
        deskCards: [],
        tiptab: {onshow: false, tiptxt: ''}
    }),
    mutations: {
        setPlayers(state: GameViewState, players: PlayerView[]) {
            state.players = players
        },
        setMainRolePlayer(state: GameViewState, player: PlayerView) {
            state.mainRolePlayer = player
        },
        setMainRoleHandCards(state: GameViewState, handcards: CardView[]) {
            state.mainRoleHandCards = handcards
        },
        setLogs(state: GameViewState, msg: string) {
            const index = state.logs.length + 1
            state.logs.unshift(index + " ." + msg)
        },
        hpReduceAction(state: GameViewState, player: Player) {
            if (state.mainRolePlayer && state.mainRolePlayer.player.equals(player)) {
                state.mainRolePlayer.hpReduce = !state.mainRolePlayer.hpReduce
                return
            }
            for(const p of state.players) {
                if (p.player.equals(player)) {
                    p.hpReduce = !p.hpReduce
                }
            }
        },
        clearDeskCard(state: GameViewState) {
            state.deskCards = []
        },
        appendDeskCard(state: GameViewState, card: Card) {
            if (card.cardProperties.source && card.cardProperties.target) {
                const firstLine = card.cardProperties.source.name
                const nextLine = card.colorCN() + card.numberCN() + card.info()
                const lastLine = card.cardProperties.target.name
                state.deskCards.push({firstLine, nextLine, lastLine})
            }
        },
        defineDeskCard(state: GameViewState, info: DeskCardInfoView) {
            state.deskCards.push(info)
        },
        waitForPickCard(state: GameViewState, {canPickCards, canPickMin, canPickMax}: {canPickCards: Card[], canPickMin: number, canPickMax: number}) {
            state.canPickMin = canPickMin
            state.canPickMax = canPickMax
            const mainRoleHandCards = state.mainRoleHandCards
            for (const mainRoleHandCard of mainRoleHandCards) {
                for(const canPickCard of canPickCards) {
                    if (mainRoleHandCard.card.equals(canPickCard)) {
                        mainRoleHandCard.canPick = true
                    }
                }
            }
        },
        waitForPickAllTypeCard(state: GameViewState, {player, canPickMin, canPickMax, pickRange}: {player: Player, canPickMin: number, canPickMax: number, pickRange: CardType<Card>[]|undefined}) {
            state.canPickMin = canPickMin
            state.canPickMax = canPickMax
            const players = state.players
            const candidateView = []
            for(const pv of players) {
                if (player.equals(pv.player)) {
                    pv.canPick = true
                    for (const eqview of pv.equipmentAreas) {
                        if (eqview) {
                            candidateView.push(eqview)
                        }
                    }
                    for (const jdgView of pv.judgeAreas) {
                        candidateView.push(jdgView)
                    }
                }
            }
            if (pickRange) {
                for(const pv of candidateView) {
                    for (const cardType of pickRange) {
                        if (pv instanceof cardType) {
                            pv.canPick = true
                        }
                    }
                }
            } else {
                for(const pv of candidateView) {
                    pv.canPick = true
                }
            }

        },
        waitForPickPlayer(state: GameViewState, {canPickPlayers, canPickMin, canPickMax}: {canPickPlayers: Player[], canPickMin: number, canPickMax: number}) {
            state.canPickMin = canPickMin
            state.canPickMax = canPickMax
            const players = state.players
            const mainRolePlayer = state.mainRolePlayer
            // 判断是否能选自己
            if (mainRolePlayer) {
                for(const canpick of canPickPlayers) {
                    if (canpick.equals(mainRolePlayer.player)) {
                        mainRolePlayer.canPick = true
                    }
                }
            }
            

            for(const pv of players) {
                for(const canpick of canPickPlayers) {
                    if (canpick.equals(pv.player)) {
                        pv.canPick = true
                    }
                }
            }

        }
    },
    actions: {
        updateView({ commit }: {commit: any}, payload: GameView) {
            updateView0(commit, payload)
        },
        updateViewAsync({ commit }: {commit: any}, payload: GameView) {
            setTimeout(() => {
                updateView0(commit, payload)
            }, 100)
        },
        hpReduceAction({ commit }: {commit: any}, player: Player) {
            commit('hpReduceAction', player)
        },
        combineDeskCardActions({ commit }: {commit: any}, {actionName, args}: {actionName:string, args?: any}) {
            commit(actionName, args)
        },
        waitForPickCard({ commit }: {commit: any}, {canPickCards, canPickMin, canPickMax}: {canPickCards: Card[], canPickMin: number,canPickMax: number}) {
            commit('waitForPickCard', {canPickCards, canPickMin, canPickMax})
        },
        waitForPickPlayer({ commit }: {commit: any}, {canPickPlayers, canPickMin, canPickMax}: {canPickPlayers: Player[], canPickMin: number,canPickMax: number}) {
            commit('waitForPickPlayer', {canPickPlayers, canPickMin, canPickMax} )
        },
        waitForPickAllTypeCard({ commit }: {commit: any}, {player, canPickMin, canPickMax, pickRange}: {player: Player, canPickMin: number, canPickMax: number, pickRange: CardType<Card>[]|undefined}) {
            commit('waitForPickAllTypeCard', {player, canPickMin, canPickMax, pickRange})
        },

        appendLog({ commit }: {commit: any}, msg: string) {
            commit('setLogs', msg)
        }
    },
    getters: {
        displayLogs(state: any): string[] {
            return state.logs.slice(0,10)
        },
        selectedCardNum(state: any): number {
            const mainRoleHandCards = state.mainRoleHandCards
            let res = 0
            for (const card of mainRoleHandCards) {
                if (card.selected) {
                    res ++
                }
            }
            return res
        },
        currentHP(state: GameViewState): string {
            let res = ''
            if (state.mainRolePlayer) {
                res = state.mainRolePlayer.player.currentHP + '/' + state.mainRolePlayer.player.maxHP
            }
            return res
        },
        selectedCards(state: any): Card[] {
            const mainRoleHandCards:CardView[] = state.mainRoleHandCards
            return mainRoleHandCards.filter(t => t.selected).map(t => t.card)
        },
        selectedPlayers(state: GameViewState): Player[] {
            const players = state.players
            const candidateSelected = players.filter(t => t.selected).map(t => t.player)
            if (state.mainRolePlayer && state.mainRolePlayer.selected) {
                candidateSelected.push(state.mainRolePlayer.player)
            }
            return candidateSelected
        },
        selectedEquipments(state: GameViewState): Card[] {
            const players = state.players
            const pvs = players.filter(t => t.selected)
            const res:Card[] = []
            if (pvs.length > 0) {
                const selectedPlayerView = pvs[0]
                for (const eqv of selectedPlayerView.equipmentAreas) {
                    if (eqv && eqv.selected) {
                        res.push(eqv.card)
                    }
                }
            }
            
            return res
        },
        selectedEquipmentsAndDelayJudge(state: GameViewState): Card[] {
            const players = state.players
            const pvs = players.filter(t => t.selected)
            const res:Card[] = []
            if (pvs.length > 0) {
                const selectedPlayerView = pvs[0]
                for (const eqv of selectedPlayerView.equipmentAreas) {
                    if (eqv && eqv.selected) {
                        res.push(eqv.card)
                    }
                }

                for (const jgv of selectedPlayerView.judgeAreas) {
                    if (jgv.selected) {
                        res.push(jgv.card)
                    }
                }
            }

            return res
        },
        selectedPlayerNum(state: GameViewState): number {
            const players = state.players
            let res = 0
            for (const player of players) {
                if (player.selected) {
                    res ++
                }
            }
            if (state.mainRolePlayer && state.mainRolePlayer.selected) {
                res ++
            }
            return res
        },
    }
}


export const ViewStoreDispather = {
    waitForPickPlayer(store: any, {canPickPlayers, canPickMin, canPickMax}: {canPickPlayers: Player[], canPickMin: number,canPickMax: number}): void {
        store.dispatch('viewStore/waitForPickPlayer', {canPickPlayers, canPickMin, canPickMax})
    },

    appendLog(store: any, msg: string): void {
        store.dispatch('viewStore/appendLog', msg)
    },
    hpReduceAction(store: any, player: Player) {
        store.dispatch('viewStore/hpReduceAction', player)
    },
    clearDeskCard(store: any) {
        store.dispatch('viewStore/combineDeskCardActions', {actionName: 'clearDeskCard'})
    },
    appendDeskCard(store: any, card: Card) {
        store.dispatch('viewStore/combineDeskCardActions', {actionName: 'appendDeskCard',args: card})
    },
    defineDeskCard(store: any, info: DeskCardInfoView) {
        store.dispatch('viewStore/combineDeskCardActions', {actionName: 'defineDeskCard',args: info})
    },

    waitForPickCard(store: any, {canPickCards, canPickMin, canPickMax}: {canPickCards: Card[], canPickMin: number,canPickMax: number}): void {
        store.dispatch('viewStore/waitForPickCard', {canPickCards, canPickMin, canPickMax})
    },
    waitForPickAllTypeCard(store: any, player: Player, canPickMin: number, canPickMax: number, pickRange: CardType<Card>[]|undefined) {
        store.dispatch('viewStore/waitForPickAllTypeCard', {player, canPickMin, canPickMax, pickRange})
    },
    updateView(store: any, payload: GameView): void {
        store.dispatch('viewStore/updateView', payload)
    },
    selectedCards(store: any): any {
        const resf = computed(() => store.getters['viewStore/selectedCards'])
        return resf.value
    },
    selectedEquipments(store: any): any {
        const resf = computed(() => store.getters['viewStore/selectedEquipments'])
        return resf.value
    },
    selectedEquipmentsAndDelayJudge(store: any): any {
        const resf = computed(() => store.getters['viewStore/selectedEquipmentsAndDelayJudge'])
        return resf.value
    },
    selectedPlayers(store: any): any {
        const resf = computed(() => store.getters['viewStore/selectedPlayers'])
        return resf.value
    },

    selectedCardNum(store: any): any {
        const res = this.selectedCardNumComputed(store)
        return res.value
    },
    selectedCardNumComputed(store: any): any {
        return computed(() => store.getters['viewStore/selectedCardNum'])
    },
    canPickMin(store: any): number {
        return store.state.viewStore.canPickMin
    },
    canPickMax(store: any): number {
        return store.state.viewStore.canPickMax
    },
    selectedPlayerNum(store: any): number {
        return store.getters['viewStore/selectedPlayerNum']
    }
}
